#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
一等奖中奖情况爬虫
抓取各省份一等奖中奖详情信息
"""

import requests
import json
import re
from typing import Dict, List, Optional
from datetime import datetime
from loguru import logger
from bs4 import BeautifulSoup
import time

import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))

from database import db_manager


class PrizeDetailSpider:
    """一等奖中奖情况爬虫"""
    
    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
            'Accept-Encoding': 'gzip, deflate',
            'Connection': 'keep-alive',
            'Upgrade-Insecure-Requests': '1'
        })
    
    def crawl_ssq_prize_details(self, period: str) -> Optional[Dict]:
        """抓取双色球一等奖中奖详情
        
        Args:
            period: 期号，如 '2025105'
            
        Returns:
            包含各省份中奖情况的字典
        """
        try:
            logger.info(f"开始抓取双色球 {period} 期一等奖中奖详情")
            
            # 中国福彩网一等奖详情页面
            url = f"https://www.cwl.gov.cn/cwl_admin/front/cwlkj/search/kjxx/findDrawNotice"
            
            # 请求参数
            params = {
                'name': 'ssq',
                'issueCount': 1,
                'issueStart': period,
                'issueEnd': period
            }
            
            response = self.session.get(url, params=params, timeout=30)
            response.raise_for_status()
            
            data = response.json()
            
            if not data.get('result') or not data['result']:
                logger.warning(f"未找到双色球 {period} 期数据")
                return None
            
            result = data['result'][0]
            
            # 解析一等奖详情
            prize_details = self._parse_ssq_prize_details(result, period)
            
            logger.info(f"成功抓取双色球 {period} 期一等奖详情: {len(prize_details.get('provinces', []))} 个省份")
            return prize_details
            
        except Exception as e:
            logger.error(f"抓取双色球 {period} 期一等奖详情失败: {e}")
            return None
    
    def crawl_dlt_prize_details(self, period: str) -> Optional[Dict]:
        """抓取大乐透一等奖中奖详情
        
        Args:
            period: 期号，如 '25104'
            
        Returns:
            包含各省份中奖情况的字典
        """
        try:
            logger.info(f"开始抓取大乐透 {period} 期一等奖中奖详情")
            
            # 体彩网一等奖详情页面
            url = f"https://webapi.sporttery.cn/gateway/lottery/getHistoryPageListV1.qry"
            
            # 请求参数
            params = {
                'gameNo': '85',  # 大乐透游戏编号
                'provinceId': '0',
                'pageSize': '1',
                'pageNo': '1',
                'isVerify': '1',
                'termList': period
            }
            
            response = self.session.get(url, params=params, timeout=30)
            response.raise_for_status()
            
            data = response.json()
            
            if not data.get('value', {}).get('list'):
                logger.warning(f"未找到大乐透 {period} 期数据")
                return None
            
            result = data['value']['list'][0]
            
            # 解析一等奖详情
            prize_details = self._parse_dlt_prize_details(result, period)
            
            logger.info(f"成功抓取大乐透 {period} 期一等奖详情: {len(prize_details.get('provinces', []))} 个省份")
            return prize_details
            
        except Exception as e:
            logger.error(f"抓取大乐透 {period} 期一等奖详情失败: {e}")
            return None
    
    def _parse_ssq_prize_details(self, result: Dict, period: str) -> Dict:
        """解析双色球一等奖详情数据"""
        prize_details = {
            'lottery_type': 'ssq',
            'period': period,
            'draw_date': result.get('date', ''),
            'total_first_prize_winners': 0,
            'total_first_prize_amount': 0,
            'provinces': []
        }
        
        # 解析奖级信息
        prizes_info = result.get('prizegrades', [])
        
        # 查找一等奖信息
        first_prize = None
        for prize in prizes_info:
            if prize.get('type') == 1:  # 一等奖
                first_prize = prize
                break
        
        if not first_prize:
            logger.warning(f"双色球 {period} 期未找到一等奖信息")
            return prize_details
        
        prize_details['total_first_prize_winners'] = first_prize.get('typenum', 0)
        prize_details['total_first_prize_amount'] = first_prize.get('typemoney', 0)
        
        # 解析各省份中奖情况
        provinces_info = result.get('prov', [])
        
        for prov in provinces_info:
            province_data = {
                'province_name': prov.get('name', ''),
                'province_code': prov.get('code', ''),
                'first_prize_winners': 0,
                'first_prize_amount': 0
            }
            
            # 解析该省份的奖级信息
            prov_prizes = prov.get('prizegrades', [])
            for prize in prov_prizes:
                if prize.get('type') == 1:  # 一等奖
                    province_data['first_prize_winners'] = prize.get('typenum', 0)
                    province_data['first_prize_amount'] = prize.get('typemoney', 0)
                    break
            
            if province_data['first_prize_winners'] > 0:
                prize_details['provinces'].append(province_data)
        
        return prize_details
    
    def _parse_dlt_prize_details(self, result: Dict, period: str) -> Dict:
        """解析大乐透一等奖详情数据"""
        prize_details = {
            'lottery_type': 'dlt',
            'period': period,
            'draw_date': result.get('lotteryDrawTime', ''),
            'total_first_prize_winners': 0,
            'total_first_prize_amount': 0,
            'provinces': []
        }
        
        # 解析奖级信息
        prizes_info = result.get('lotteryDrawResult', [])
        
        # 查找一等奖信息
        first_prize = None
        for prize in prizes_info:
            if prize.get('grade') == 1:  # 一等奖
                first_prize = prize
                break
        
        if not first_prize:
            logger.warning(f"大乐透 {period} 期未找到一等奖信息")
            return prize_details
        
        prize_details['total_first_prize_winners'] = first_prize.get('stakeCount', 0)
        prize_details['total_first_prize_amount'] = first_prize.get('stakeAmount', 0)
        
        # 大乐透的省份详情需要额外请求
        province_details = self._fetch_dlt_province_details(period)
        if province_details:
            prize_details['provinces'] = province_details
        
        return prize_details
    
    def _fetch_dlt_province_details(self, period: str) -> List[Dict]:
        """获取大乐透各省份中奖详情"""
        try:
            # 体彩网省份详情接口
            url = f"https://webapi.sporttery.cn/gateway/lottery/getWinStationInfo.qry"
            
            params = {
                'gameNo': '85',
                'termCode': period,
                'gradeType': '1'  # 一等奖
            }
            
            response = self.session.get(url, params=params, timeout=30)
            response.raise_for_status()
            
            data = response.json()
            
            if not data.get('value', {}).get('list'):
                return []
            
            provinces = []
            for item in data['value']['list']:
                province_data = {
                    'province_name': item.get('provinceName', ''),
                    'province_code': item.get('provinceId', ''),
                    'first_prize_winners': item.get('stakeCount', 0),
                    'first_prize_amount': item.get('stakeAmount', 0),
                    'station_info': item.get('stationName', '')  # 投注站信息
                }
                provinces.append(province_data)
            
            return provinces
            
        except Exception as e:
            logger.error(f"获取大乐透 {period} 期省份详情失败: {e}")
            return []
    
    def save_prize_details(self, prize_details: Dict) -> bool:
        """保存一等奖中奖详情到数据库
        
        Args:
            prize_details: 中奖详情数据
            
        Returns:
            保存是否成功
        """
        try:
            # 保存主表数据
            main_sql = """
            INSERT INTO lottery_prize_details 
            (lottery_type, period, draw_date, total_first_prize_winners, 
             total_first_prize_amount, created_at, updated_at)
            VALUES (%s, %s, %s, %s, %s, NOW(), NOW())
            ON DUPLICATE KEY UPDATE
            total_first_prize_winners = VALUES(total_first_prize_winners),
            total_first_prize_amount = VALUES(total_first_prize_amount),
            updated_at = NOW()
            """
            
            main_params = (
                prize_details['lottery_type'],
                prize_details['period'],
                prize_details['draw_date'],
                prize_details['total_first_prize_winners'],
                prize_details['total_first_prize_amount']
            )
            
            db_manager.execute_query(main_sql, main_params)
            
            # 清除旧的省份数据
            delete_sql = """
            DELETE FROM lottery_province_prizes 
            WHERE lottery_type = %s AND period = %s
            """
            db_manager.execute_query(delete_sql, (prize_details['lottery_type'], prize_details['period']))
            
            # 保存省份数据
            if prize_details.get('provinces'):
                province_sql = """
                INSERT INTO lottery_province_prizes 
                (lottery_type, period, province_name, province_code, 
                 first_prize_winners, first_prize_amount, station_info, created_at)
                VALUES (%s, %s, %s, %s, %s, %s, %s, NOW())
                """
                
                for province in prize_details['provinces']:
                    province_params = (
                        prize_details['lottery_type'],
                        prize_details['period'],
                        province['province_name'],
                        province.get('province_code', ''),
                        province['first_prize_winners'],
                        province['first_prize_amount'],
                        province.get('station_info', '')
                    )
                    db_manager.execute_query(province_sql, province_params)
            
            logger.info(f"成功保存 {prize_details['lottery_type']} {prize_details['period']} 期一等奖详情")
            return True
            
        except Exception as e:
            logger.error(f"保存一等奖详情失败: {e}")
            return False
    
    def crawl_and_save_prize_details(self, lottery_type: str, period: str) -> bool:
        """抓取并保存一等奖中奖详情
        
        Args:
            lottery_type: 彩种类型 (ssq, dlt)
            period: 期号
            
        Returns:
            是否成功
        """
        try:
            prize_details = None
            
            if lottery_type == 'ssq':
                prize_details = self.crawl_ssq_prize_details(period)
            elif lottery_type == 'dlt':
                prize_details = self.crawl_dlt_prize_details(period)
            else:
                logger.warning(f"不支持的彩种类型: {lottery_type}")
                return False
            
            if prize_details:
                return self.save_prize_details(prize_details)
            
            return False
            
        except Exception as e:
            logger.error(f"抓取并保存 {lottery_type} {period} 期一等奖详情失败: {e}")
            return False
    
    def batch_crawl_recent_periods(self, lottery_type: str, count: int = 10) -> int:
        """批量抓取最近几期的一等奖详情
        
        Args:
            lottery_type: 彩种类型
            count: 抓取期数
            
        Returns:
            成功抓取的期数
        """
        try:
            # 从数据库获取最近的期号
            sql = """
            SELECT period FROM lottery_results 
            WHERE lottery_type = %s 
            ORDER BY period DESC 
            LIMIT %s
            """
            
            results = db_manager.execute_query(sql, (lottery_type, count))
            
            if not results:
                logger.warning(f"未找到 {lottery_type} 的期号数据")
                return 0
            
            success_count = 0
            for result in results:
                period = result['period']
                if self.crawl_and_save_prize_details(lottery_type, period):
                    success_count += 1
                
                # 避免请求过于频繁
                time.sleep(2)
            
            logger.info(f"批量抓取 {lottery_type} 完成: {success_count}/{len(results)} 期成功")
            return success_count
            
        except Exception as e:
            logger.error(f"批量抓取 {lottery_type} 一等奖详情失败: {e}")
            return 0


def main():
    """测试函数"""
    spider = PrizeDetailSpider()
    
    # 测试抓取双色球最新一期
    print("测试抓取双色球一等奖详情...")
    success_count = spider.batch_crawl_recent_periods('ssq', 1)
    print(f"双色球抓取结果: {success_count} 期成功")
    
    # 测试抓取大乐透最新一期
    print("测试抓取大乐透一等奖详情...")
    success_count = spider.batch_crawl_recent_periods('dlt', 1)
    print(f"大乐透抓取结果: {success_count} 期成功")


if __name__ == "__main__":
    main()
